package io.rocketman.serialize.kryo;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import io.rocketman.common.plugin.Plugin;
import io.rocketman.serialize.Serializer;
import io.rocketman.serialize.kryo.util.KryoUtils;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * @author He Peng
 * @create 2018-05-26 15:18
 * @update 2018-05-26 15:18
 * @updatedesc : 更新说明
 * @see
 */

@Plugin("kryo")
public class KryoSerializer implements Serializer {

    public static final int DEFAULT_BUFFER_BYTE_SIZE = 600;

    @Override
    public byte[] serialize(Object obj) {
        return serialize(obj , DEFAULT_BUFFER_BYTE_SIZE);
    }

    @Override
    public void serialize(OutputStream output, Object obj) {
        serialize(output , obj , DEFAULT_BUFFER_BYTE_SIZE);
    }

    @Override
    public <T> T deserialize(byte[] bytes, Class<T> cls) {
        return deserialize(bytes , cls , DEFAULT_BUFFER_BYTE_SIZE);
    }

    @Override
    public <T> T deserialize(InputStream input, Class<T> cls) {
        return deserialize(input , cls , DEFAULT_BUFFER_BYTE_SIZE);
    }

    @Override
    public byte[] serialize(Object obj, int bufferSize) {
        Kryo kryo = getKryo(obj.getClass());
        Output output = new Output(bufferSize);
        kryo.writeObject(output , obj);
        return output.toBytes();
    }

    @Override
    public void serialize(OutputStream output, Object obj, int bufferSize) {
        Kryo kryo = getKryo(obj.getClass());
        kryo.writeObject(new Output(output , bufferSize) , obj);
    }

    @Override
    public <T> T deserialize(byte[] bytes, Class<T> cls, int bufferSize) {
        Kryo kryo = getKryo(cls);
        Input input = new Input(new ByteArrayInputStream(bytes) , bufferSize);
        return kryo.readObject(input , cls);
    }

    @Override
    public <T> T deserialize(InputStream input, Class<T> cls, int bufferSize) {
        Kryo kryo = getKryo(cls);
        return kryo.readObject(new Input(input , bufferSize) , cls);
    }

    private Kryo getKryo(Class cls) {
        Kryo kryo = ThreadBindingKryo.get();
        KryoUtils.maybeRegisterClass(kryo , cls);
        return kryo;
    }
}
